/**
 * 
 */
package org.vsg.common.jobscheduler.web;

import java.util.Properties;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.sql.DataSource;

import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.vsg.common.configration.PropertiesSupport;
import org.vsg.common.jobscheduler.factory.SpringSchedulerFactory;

/**
 * @author Bill Vison
 *
 */
public class SpringQuartzInitializerListener extends QuartzInitializerListener {

    public static final String QUARTZ_FACTORY_KEY = "org.quartz.impl.StdSchedulerFactory.KEY";

    private boolean performShutdown = true;

    private Scheduler scheduler = null;

	protected static final Logger logger = LoggerFactory.getLogger(SpringQuartzInitializerListener.class);   
    
    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     *
     * Interface.
     *
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    public void contextInitialized(ServletContextEvent sce) {

        ServletContext servletContext = sce.getServletContext();    	
    	
		WebApplicationContext appContext = 
			(WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    	
		String[] beansName = appContext.getBeanNamesForType(DataSource.class);    	
    	
		DataSource ds = null;
		if (beansName.length == 1) {
			ds = (DataSource)appContext.getBean( beansName[0] );
		}
		else if (beansName.length > 1) {
			String dsName = servletContext.getInitParameter("spring-ds-name");
			for (int i = 0 ; i < beansName.length ; i++) {
				if (beansName[i].equals(dsName)) {
					ds =  (DataSource)appContext.getBean( beansName[i] );
					break;
				}
			}
		}
		
		
		beansName = appContext.getBeanNamesForType(PropertiesSupport.class); 
		Properties properties = null;
		PropertiesSupport ps = null;
		if (beansName.length >= 1) {
			ps = (PropertiesSupport)appContext.getBean( beansName[0] );
			properties = ps.getProperties();
		}
		
		
        logger.info("Quartz Initializer Servlet loaded, initializing Scheduler...");


        SpringSchedulerFactory factory;
        try {

            String shutdownPref = servletContext.getInitParameter("shutdown-on-unload");

            if (shutdownPref != null) {
                performShutdown = Boolean.valueOf(shutdownPref).booleanValue();
            }

            // get Properties and handle factory
            factory = new SpringSchedulerFactory();
            factory.setDataSource( ds );
            factory.setProperties(properties);

            // Always want to get the scheduler, even if it isn't starting, 
            // to make sure it is both initialized and registered.
            scheduler = factory.getScheduler();

            // Should the Scheduler being started now or later
            String startOnLoad = servletContext
                    .getInitParameter("start-scheduler-on-load");

            int startDelay = 0;
            String startDelayS = servletContext.getInitParameter("start-delay-seconds");
            try {
                if(startDelayS != null && startDelayS.trim().length() > 0)
                    startDelay = Integer.parseInt(startDelayS);
            } catch(Exception e) {
               logger.info("Cannot parse value of 'start-delay-seconds' to an integer: " + startDelayS + ", defaulting to 5 seconds.");
                startDelay = 5;
            }

            /*
             * If the "start-scheduler-on-load" init-parameter is not specified,
             * the scheduler will be started. This is to maintain backwards
             * compatability.
             */
            if (startOnLoad == null || (Boolean.valueOf(startOnLoad).booleanValue())) {
                if(startDelay <= 0) {
                    // Start now
                    scheduler.start();
                    logger.info("Scheduler has been started...");
                }
                else {
                    // Start delayed
                    scheduler.startDelayed(startDelay);
                    logger.info("Scheduler will start in " + startDelay + " seconds.");
                }
            } else {
                logger.info("Scheduler has not been started. Use scheduler.start()");
            }

            String factoryKey = 
                servletContext.getInitParameter("servlet-context-factory-key");
            if (factoryKey == null) {
                factoryKey = QUARTZ_FACTORY_KEY;
            }

            logger.info("Storing the Quartz Scheduler Factory in the servlet context at key: "
                    + factoryKey);
            servletContext.setAttribute(factoryKey, factory);

        } catch (Exception e) {
            logger.info("Quartz Scheduler failed to initialize: " + e.toString());
            e.printStackTrace();
        }
    }

    public void contextDestroyed(ServletContextEvent sce) {

        if (!performShutdown) {
            return;
        }

        try {
            if (scheduler != null) {
                scheduler.shutdown();
            }
        } catch (Exception e) {
            logger.info("Quartz Scheduler failed to shutdown cleanly: " + e.toString());
            e.printStackTrace();
        }

        logger.info("Quartz Scheduler successful shutdown.");
    }
	
	
}
